// Includes
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <limits.h>
#include <iostream>
#include <string>
#include <ctime>
#include <cstdlib>

//Incluyo la clase Mersenne-Twister para la generación de números aleatorios en C++
#include "utils/mt.h"

//Incluyo la clase Random para la generación de números aleatorios en CUDA
#include "utils/Random.cu"

//Incluyo la clase cuPrintf para poder imprimir desde GPU
#include "utils/cuPrintf.cu"

//Incluyo la clase parser.cpp para obetener los parametros
#include "utils/parser.cpp"

//Incluyo la clase global.cu  que contiene las variables y funciones globales
#include "utils/global.cu"

//Incluyo las clases binaria, entera, permutacion y real, las cuales tienen un hilo cada 2 individuos y un bloque por poblacion
#include "representaciones/binaria.cu"
#include "representaciones/entera.cu"
#include "representaciones/permutacion.cu"
#include "representaciones/real.cu"

//Incluyo las clases binariaGen, enteraGen y realGen, las cuales tienen un hilo por gen y un bloque cada 2 individuos
#include "representaciones/binariaGen.cu"
#include "representaciones/enteraGen.cu"
#include "representaciones/realGen.cu"

//Semilla aleatoria a utilizar.
#define SEMILLA (time(NULL))

using namespace std;


//////////////////////
// Program main
//////////////////////

int main( int argc, char** argv) {
	cudaPrintfInit();

	float * parametros = obtenerParametros();
	asignarParametros(parametros);

	dim3 tamGridAsig(1,1); //Grid dimensión
	dim3 tamBlockAsig(1,1,1); //Block dimensión

	int tamVectorParametros = sizeof(float)*cantidadParametros;

	float *parametrosDevice;
	cudaMalloc(&parametrosDevice, tamVectorParametros);

	cudaMemcpy (parametrosDevice, parametros, tamVectorParametros, cudaMemcpyHostToDevice);
	//asignacion de parametros en GPU
	asignarParametrosDevice<<<tamGridAsig, tamBlockAsig>>>(parametrosDevice);

	totalGenesGPU = cantidadPoblacionesGPU * cantCromosomasPoblacion * cantGenesEnCromosoma;
	totalGenesCPU = cantidadPoblacionesCPU * cantCromosomasPoblacion * cantGenesEnCromosoma;
	totalIndividuosGPU = cantCromosomasPoblacion*cantidadPoblacionesGPU;
	totalIndividuosCPU = cantCromosomasPoblacion*cantidadPoblacionesCPU;

	if (tipoRepresentacion == 0 && bloquePorPoblacion == 1) {
		representacionBinaria();
	}else if(tipoRepresentacion == 0){
		representacionBinariaGen();
	}else if (tipoRepresentacion == 1 && bloquePorPoblacion == 1) {
		representacionEntera();
	}else if (tipoRepresentacion == 1){
		representacionEnteraGen();
	}else if (tipoRepresentacion == 2) {
		representacionPermutacion();
	}else if(tipoRepresentacion == 3 && bloquePorPoblacion == 1){
		representacionReal();
	}else{
		representacionRealGen();
	}


	cudaPrintfDisplay(stdout, true);
	cudaPrintfEnd();

}
